package com.siyoumi.app.modules.file.service;

import com.siyoumi.app.modules.file.entity.FileItem;
import com.siyoumi.app.sys.service.CommonApiServcie;
import com.siyoumi.component.XSpringContext;
import com.siyoumi.config.SysConfig;
import com.siyoumi.config.SysConfigConsole;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.service.SysAccsuperConfigService;
import com.siyoumi.util.*;
import com.siyoumi.component.http.InputData;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.validator.XValidator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class FileService {
    static public FileService getBean() {
        return XSpringContext.getBean(FileService.class);
    }

    @SneakyThrows
    public List<FileItem> fileList(InputData inputData) {
        String dir = inputData.input("dir", "");
        String handlerDir = getHandlerDir(dir, null);

        String imgRoot = SysConfig.getIns().getImgRoot();

        Stream<Path> listPath = Files.list(Paths.get(handlerDir));
        List<FileItem> list = listPath.map(path -> {
            File file = new File(path.toString());

            FileItem fileItem = new FileItem();
            fileItem.setFilename(path.getFileName().toString());
            fileItem.setId(fileItem.getFilename());
            fileItem.setIs_dir(file.isDirectory());
            //类型
            if (fileItem.getIs_dir()) {
                fileItem.setType("目录");
            } else {
                fileItem.setType("文件");
                if (isImg(fileItem.getId())) {
                    fileItem.setType("图片");
                } else if (isVideo(fileItem.getId())) {
                    fileItem.setType("视频");
                }
                //访问路径
                //String fileUrl = XStr.concat(imgRoot, dir, fileItem.getFilename());
                //if (!XHttpContext.getX().equals("x")) {
                //    fileUrl = XStr.concat(imgRoot, XHttpContext.getX(), "/", dir, fileItem.getFilename());
                //}
                String fileUrl = getFileUrl(dir, fileItem.getFilename());
                fileItem.setFile_url(fileUrl);
                //可编辑
                if (fileItem.getType().equals("文件")) {
                    fileItem.setDo_edit(true);
                }
            }

            return fileItem;
        }).collect(Collectors.toList());

        //目录排第1
        List<FileItem> listNew = list.stream().filter(FileItem::getIs_dir).collect(Collectors.toList());
        for (FileItem fileItem : list) {
            if (!fileItem.getIs_dir()) {
                listNew.add(fileItem);
            }
        }

        return listNew;
    }

    /**
     * 编辑
     *
     * @param inputData
     */
    public XReturn edit(InputData inputData) {
        String encTxt = inputData.input("txt");
        String filename = inputData.input("filename");
        String dir = inputData.input("dir");

        String fileExt = getFileExt(filename);
        if (!XFile.getFileExtenstions().contains(fileExt)) {
            return EnumSys.FILE_EXTENSTION.getR();
        }
        String handlerDir = getHandlerDir(dir, filename);
        if (!XFile.exists(handlerDir)) {
            return EnumSys.FILE_EXISTS.getR();
        }

        //String txt = decAes(encTxt);
        String txt = encTxt;

        XFile.putContent(handlerDir, txt);

        return XReturn.getR(0);
    }

    /**
     * 同步svn
     */
    public XReturn syncSvn() {
        SysConfigConsole console = SysConfig.getIns().getConsole();
        if (console == null
                || XStr.isNullOrEmpty(console.getAddress())
                || XStr.isNullOrEmpty(console.getLongToken())
                || XStr.isNullOrEmpty(console.getCmdIndex())
        ) {
            return EnumSys.ERR_VAL.getR("请配置console参数");
        }

        String url = XStr.concat(console.getAddress(), "api/cmd?token=", console.getLongToken(), "&type=", console.getCmdIndex());
        XReturn r;
        try {
            XHttpClient client = XHttpClient.getInstance();
            String returnStr = client.get(url, null);
            log.debug("url:{}", url);
            r = XReturn.parse(returnStr);
        } catch (Exception ex) {
            ex.printStackTrace();
            r = EnumSys.SYS.getR("同步接口异常");
            r.setData("message", ex.getMessage());
            r.setData("url", url);
        }

        if (r.err()) {
            r.setErrMsg("console:", r.getErrMsg());
            r.setErrCode(123456);
        }

        return r;
    }

    /**
     * 判断同步是否完成
     *
     * @param key
     */
    public XReturn syncSvnDone(String key) {
        SysConfigConsole console = SysConfig.getIns().getConsole();

        String url = XStr.concat(console.getAddress(), "api/cmd_msg?token=", console.getLongToken()
                , "&key=", XStr.urlEnc(key));
        log.debug("url:{}", url);
        XHttpClient client = XHttpClient.getInstance();
        String returnStr = client.get(url, null);

        XReturn r = XReturn.parse(returnStr);
        if (r.err()) {
            r.setErrMsg("console:", r.getErrMsg());
            r.setErrCode(123456);
        }

        return r;
    }

    /**
     * 文件上传
     *
     * @param file
     * @param inputData
     */
    public XReturn uploadFile(MultipartFile file, InputData inputData) {
        String dir = inputData.input("dir");
        String checked = inputData.input("checked", "");

        Boolean checkExistsFile = checked.equals("true");
        String handlerDir = getHandlerDir(dir, null);
        if (!XFile.exists(handlerDir)) {
            return XReturn.getR(20054, "目录不存在");
        }

        List<String> ext = new ArrayList<>();
        ext.addAll(XFile.getFileExtenstions());
        ext.addAll(XFile.getImgExtenstions());

        String filename = file.getOriginalFilename();
        String saveFilePath = getHandlerDir(dir, filename);
        XLog.debug(this.getClass(), "saveFilePath:", saveFilePath);
        if (checkExistsFile) {
            if (XFile.exists(saveFilePath)) {
                return XReturn.getR(20055, "同名文件已存在");
            }
        }

        return CommonApiServcie.getBean().uploadFile(file, ext, SysConfig.getIns().getUploadFileSizeMax(), saveFilePath);
    }

    /**
     * 目录或者文件重命名
     */
    public XReturn rename(InputData inputData) {
        String dir = inputData.input("dir");
        String oldName = inputData.input("old_name");
        String newName = inputData.input("new_name");
        if (XStr.isNullOrEmpty(dir)
                || XStr.isNullOrEmpty(oldName)
                || XStr.isNullOrEmpty(newName)) {
            return EnumSys.MISS_VAL.getR();
        }

        String oldPath = getHandlerDir(dir, oldName);
        String newPath = getHandlerDir(dir, newName);

        boolean res = new File(oldPath).renameTo(new File(newPath));
        XReturn r = XReturn.getR(0);
        r.setData("result", res);
        return r;
    }

    /**
     * 添加目录
     */
    public XReturn addDir(InputData inputData) {
        String dir = inputData.input("dir");
        String dirName = inputData.input("dir_name");
        if (XStr.isNullOrEmpty(dirName)) {
            return EnumSys.MISS_VAL.getR();
        }

        String dirPath = getHandlerDir(dir, dirName);
        File file = new File(dirPath);
        if (file.exists()) {
            return XReturn.getR(20078, "目录已存在");
        }

        file.mkdir();

        return XReturn.getR(0);
    }

    /**
     * 删除文件
     */
    public XReturn del(InputData inputData) {
        String dir = inputData.input("dir");
        String files = inputData.input("files");
        if (XStr.isNullOrEmpty(dir)
                || XStr.isNullOrEmpty(files)) {
            return EnumSys.MISS_VAL.getR();
        }

        List<String> fileArr = Arrays.asList(files.split(","));
        for (String filename : fileArr) {
            String filePath = getHandlerDir(dir, filename);
            File file = new File(filePath);
            file.deleteOnExit();
        }

        return XReturn.getR(0);
    }

    /**
     * 获取处理目录
     */
    public String getHandlerDir(String dir, String fileName) {
        if (XStr.hasAnyText(dir)) {
            if (dir.contains(".\\") || dir.contains("./")) {
                XValidator.err(20282, "非法目录");
            }
        }

        String appId = getAppId();

        String path = getPathX(appId);
        if (XStr.hasAnyText(dir)) {
            if (XStr.endsWith(path, "\\")) {
                path = path.substring(0, path.length() - 1);
            } else if (XStr.endsWith(path, "/")) {
                path = path.substring(0, path.length() - 1);
            }
            path = XStr.concat(path, "/", dir);
        }

        if (XStr.hasAnyText(fileName)) {
            if (XStr.endsWith(path, "/")) {
                path = path.substring(0, path.length() - 1);
            }

            path = XStr.concat(path, "/", fileName);
        }

        log.info("getHandlerDir:{}", path);
        return path;
    }

    public String getAppId() {
        String appId = XHttpContext.getAppId();
        if (appId.equals("file")) {
            appId = "";
        }
        return appId;
    }


    /**
     * x
     * /_update
     * 其他
     * /res
     */
    public String getPathX(String appId) {
        String uploadPath = SysConfig.getIns().getUploadPath();
        if (!SysAccsuperConfigService.isCenter()) {
            uploadPath = SysConfig.getIns().getResPath();
            if (XStr.isNullOrEmpty(uploadPath)) {
                XValidator.err(50324, "未配置res目录");
            }
            //uploadPath = XStr.concat(uploadPath, XHttpContext.getX());
        }
        if (XStr.hasAnyText(appId)) {
            uploadPath += appId;
        }
        XFile.mkdirs(uploadPath);

        return uploadPath;
    }

    /**
     * 访问路径
     *
     * @param dir
     * @param fileName
     */
    public String getFileUrl(String dir, String fileName) {
        String appId = getAppId();

        String imgRoot = SysConfig.getIns().getImgRoot();
        String url = imgRoot;
        if (!SysAccsuperConfigService.isCenter()) {
            //res/1.jpg
            url = XStr.concat(imgRoot, "res");
        }

        if (XStr.hasAnyText(appId)) {
            //res/prize/t_001/1.jpg
            url += "/" + appId;
        }
        url += XStr.concat("/", dir, fileName);

        return url;
    }


    /**
     * 获取文件后缀
     */
    public String getFileExt(String filename) {
        if (XStr.isNullOrEmpty(filename)) {
            return "";
        }

        XLog.debug(this.getClass(), "filename:", filename);
        String ext = "";
        if (XStr.contains(filename, ".")) {
            String[] arr = filename.split("\\.");
            ext = arr[arr.length - 1];
        }

        return ext;
    }

    public Boolean isImg(String filename) {
        String fileExt = getFileExt(filename);
        return XFile.getImgExtenstions().contains(fileExt);
    }

    public Boolean isVideo(String filename) {
        String fileExt = getFileExt(filename);
        List<String> ex = new ArrayList<>();
        ex.add("mp4");
        return ex.contains(fileExt);
    }


    public String getAesKey() {
        return "1234567890654321";
    }

    public String getAesVi() {
        return "1234567890123456";
    }

    // 生成iv
    public AlgorithmParameters getAesViObj() throws Exception {
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(getAesVi().getBytes(StandardCharsets.UTF_8)));
        return params;
    }

    @SneakyThrows
    public String decAes(String txt) {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        Key sKeySpec = new SecretKeySpec(getAesKey().getBytes(StandardCharsets.UTF_8), "AES");
        cipher.init(Cipher.DECRYPT_MODE, sKeySpec, getAesViObj());// 初始化
        byte[] result = cipher.doFinal(txt.getBytes(StandardCharsets.UTF_8));
        return new String(result);
    }
}
